package com.mxchip.livestarmobile.mobile.ui.call

import android.app.Application
import android.os.Looper
import android.util.Log
import androidx.lifecycle.*
import androidx.lifecycle.Observer
import com.mxchip.livestarmobile.mobile.state.SystemData
import com.mxchip.livestarmobile.mobile.util.Log.MyLog
import kotlin.collections.LinkedHashSet

class RoomViewModel(application: Application) : AndroidViewModel(application) {

    enum class RoomType {
        GROUP, P2P
    }

    private val mAvDevices = MutableLiveData<List<AVDevice>>(arrayListOf())

    private val mRoomId = MutableLiveData<String>()
    private val mChannelId = MutableLiveData<String>()
    private val mCallIndex = MutableLiveData<String>()

    private val mGroupId = MutableLiveData<String>()

    private val mIsMyselfTheOnlyOneLeft = MutableLiveData<Boolean>(false)
    private val mIsSessionsCallEmpty = MutableLiveData<Boolean>(false)

    private val mSessionsJoin = MutableLiveData<Set<String>>(linkedSetOf())
    private val mSessionsCall = MutableLiveData<Set<String>>(linkedSetOf())

    private val mSessionsAll = MediatorLiveData<Set<String>>().apply { value = linkedSetOf() }
    private val mTermIdsAll = MediatorLiveData<Set<String>>().apply { value = linkedSetOf() }

    private var mRoomType: RoomType = RoomType.P2P
    var otherUserLeaved = false
    val termIdsAll: LiveData<Set<String>>
        get() = mTermIdsAll

    val sessionsJoin: LiveData<Set<String>>
        get() = mSessionsJoin

    val sessionsCall: LiveData<Set<String>>
        get() = mSessionsCall

    val sessionsAll: LiveData<Set<String>>
        get() = mSessionsAll


    val roomId: LiveData<String>
        get() = mRoomId

    val channelId: LiveData<String>
        get() = mChannelId

    val groupId: LiveData<String>
        get() = mGroupId

    val callIndex: LiveData<String>
        get() = mCallIndex

    val roomType: RoomType
        get() = mRoomType

    val isMyselfTheOnlyOneLeft: LiveData<Boolean>
        get() = mIsMyselfTheOnlyOneLeft

    val isSessionsCallEmpty: LiveData<Boolean>
        get() = mIsSessionsCallEmpty

    private val termIdsAllObserver = Observer<Any> {
        mTermIdsAll.value = getTermIdsAll()
    }

    val avDevices: LiveData<List<AVDevice>>
        get() = mAvDevices

    private val sessionsAllObserver = Observer<Any> {
        val list = linkedSetOf<String>()

        mSessionsJoin.value?.let {
            list.addAll(it)
        }

        mSessionsCall.value?.let {
            list.addAll(it)
        }

        mSessionsAll.value = list
    }


    init {
        mSessionsAll.addSource(mSessionsJoin, sessionsAllObserver)
        mSessionsAll.addSource(mSessionsCall, sessionsAllObserver)

        mTermIdsAll.addSource(mSessionsJoin, termIdsAllObserver)
        mTermIdsAll.addSource(mSessionsCall, termIdsAllObserver)

    }

    fun addAVDevice(device: AVDevice) {
        Log.e("RoomViewModel", "before" + mAvDevices.value)
        val list = mAvDevices.value
        if (list is ArrayList) {
            if (!list.contains(device)) {
                list.add(device)
            }
        }
        mAvDevices.value = list

        Log.e("RoomViewModel", "after" + mAvDevices.value)
    }

    private fun removeAVDevice(uid: String) {
        val list = mAvDevices.value?.filter {
            uid != it.uid
        }
        mAvDevices.value = list
        MyLog.logD(MyLog.AV_DEVICE_MODEL, "RoomViewModel::removeAVDevice $list")
    }

    fun replaceAVDevice(devices: List<AVDevice>) {
        mAvDevices.postValue(devices)
    }

    fun removeAVDevice(uid: String, deviceName: String) {
        val list = mAvDevices.value?.filterNot {
            uid == it.uid && deviceName == it.deviceName
        }
        mAvDevices.value = list
    }

    fun onJoinRoom(session: String) {
        Log.e("RoomViewModel", "onJoinRoom $session")

        addSessionsJoin(session)

        Log.e("RoomViewModel", "onJoinRoom sessionsJoin ${mSessionsJoin.value?.toList()?.toTypedArray()?.contentToString()}")
        Log.e("RoomViewModel", "onJoinRoom sessionsCall ${mSessionsCall.value?.toList()?.toTypedArray()?.contentToString()}")
    }

    fun onStartCallRoom(session: String) {

        Log.e("RoomViewModel", "onStartCallRoom $session")

        removeSessionsJoin(session)
        addSessionsCall(session)


        Log.e("RoomViewModel", "onStartCallRoom sessionsJoin ${mSessionsJoin.value?.toList()?.toTypedArray()?.contentToString()}")
        Log.e("RoomViewModel", "onStartCallRoom sessionsCall ${mSessionsCall.value?.toList()?.toTypedArray()?.contentToString()}")
    }

    fun onLeaveRoom(session: String) {

        Log.e("RoomViewModel", "onLeaveRoom $session")
        Log.e("RoomViewModel", "onLeaveRoom sessionsJoin ${mSessionsJoin.value?.toList()?.toTypedArray()?.contentToString()}")
        Log.e("RoomViewModel", "onLeaveRoom sessionsCall ${mSessionsCall.value?.toList()?.toTypedArray()?.contentToString()}")


        removeAVDevice(session)
        removeSessionsJoin(session)
        removeSessionsCall(session)

        val sessionsAll = linkedSetOf<String>()

        mSessionsJoin.value?.let {
            sessionsAll.addAll(it)
        }

        mSessionsCall.value?.let {
            sessionsAll.addAll(it)
        }


        Log.e("RoomViewModel", "onLeaveRoom sessionsAll ${sessionsAll.toTypedArray().contentToString()}")
        // TODO: 加入是否是自己的判断
        if (sessionsAll.size <= 1) {
//            if (mRoomType != RoomType.GROUP) {
//            }
            mIsMyselfTheOnlyOneLeft.value = true
            otherUserLeaved = true

        }

        mIsSessionsCallEmpty.value = sessionsCall.value?.isEmpty()
    }

    fun setRoomId(roomId: String) {
        mRoomId.value = roomId
    }

    fun setChannelId(channelId: String) {
        mChannelId.value = channelId
    }

    fun setCallIndex(callIndex: String) {
        mCallIndex.value = callIndex
    }

    fun setGroupId(groupId: String?) {
        mGroupId.value = groupId
        Log.e("RoomViewModel", "setGroupId ${mGroupId.value} ${Thread.currentThread()}")

        mRoomType = if (!groupId.isNullOrBlank()) {
            RoomType.GROUP
        } else {
            RoomType.P2P
        }
    }

    fun setRoomType(roomType: RoomType) {
        mRoomType = roomType
    }

    fun getTermIdsAll(): Set<String> {
        val list = linkedSetOf<String>()

        Log.e("RoomViewModel", "getTermIdsAll")

        mSessionsJoin.value?.forEach { sessionId ->

            Log.e("RoomViewModel", "getTermIdsAll mSessionsJoin ${mSessionsJoin.value?.toTypedArray()?.contentToString()}")

            val sessionSplit = sessionId.split("T")
            if (sessionSplit.size > 0) {
                val termId = sessionSplit[1]
                list.add(termId)
            }
        }

        mSessionsCall.value?.forEach { sessionId ->

            Log.e("RoomViewModel", "getTermIdsAll mSessionsCall ${mSessionsCall.value?.toTypedArray()?.contentToString()}")

            val sessionSplit = sessionId.split("T")
            if (sessionSplit.size > 0) {
                val termId = sessionSplit[1]
                list.add(termId)
            }
        }

        return list
    }

    private fun addSessionsJoin(session: String) {
        mSessionsJoin.value?.let { list ->
            if (list.contains(session)) {
                return
            }

            if (list is LinkedHashSet) {
                list.add(session)
            }
            mSessionsJoin.value = list
        }
    }

    private fun removeSessionsJoin(session: String) {
        mSessionsJoin.value?.let { list ->
            if (!list.contains(session)) {
                return
            }

            if (list is LinkedHashSet) {
                list.remove(session)
            }
            mSessionsJoin.value = list
        }
    }

    private fun addSessionsCall(session: String) {
        mSessionsCall.value?.let { list ->
            if (list.contains(session)) {
                return
            }

            if (list is LinkedHashSet) {
                list.add(session)
            }
            mSessionsCall.value = list
        }
    }

    private fun removeSessionsCall(session: String) {
        mSessionsCall.value?.let { list ->
            if (!list.contains(session)) {
                return
            }

            if (list is LinkedHashSet) {
                list.remove(session)
            }
            mSessionsCall.value = list
        }
    }

    fun resetSessionsCall(list: List<String>) {
        val hashSet = LinkedHashSet(list)
        if (Looper.myLooper() == Looper.getMainLooper()) {
            mSessionsCall.value = hashSet
        } else {
            mSessionsCall.postValue(hashSet)
        }

        val sessionsAll = linkedSetOf<String>()

        mSessionsJoin.value?.let {
            sessionsAll.addAll(it)
        }

        mSessionsCall.value?.let {
            sessionsAll.addAll(it)
        }

        Log.e("RoomViewModel", "resetSessionsCall sessionsAll ${sessionsAll.toTypedArray().contentToString()}")
        Log.e("RoomViewModel", "mIsSessionsCallEmpty ${mIsSessionsCallEmpty.value}")
        // TODO: 加入是否是自己的判断
        if (sessionsAll.size <= 1/* && mRoomType != RoomType.GROUP*/ && otherUserLeaved) {
            if (Looper.myLooper() == Looper.getMainLooper()) {
                mIsMyselfTheOnlyOneLeft.value = true
            } else {
                mIsMyselfTheOnlyOneLeft.postValue(true)
            }
        }

        if (Looper.myLooper() == Looper.getMainLooper()) {
            mIsSessionsCallEmpty.value = sessionsCall.value?.isEmpty()
        } else {
            mIsSessionsCallEmpty.postValue(sessionsCall.value?.isEmpty())
        }

    }

}
